<%
' +----------------------------------------------------------------------
' | POPASP [ ASP MVC ]
' +----------------------------------------------------------------------
' | Copyright (c) 2016 http://popasp.com All rights reserved.
' +----------------------------------------------------------------------
' | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
' +----------------------------------------------------------------------
' | Author: popasp <1737025626@qq.com>
' +----------------------------------------------------------------------
'验证类
Class POPASP_AUTOVALIDATE
	'自动验证

	public [error]		'最近错误消息
	
	Public tableName	'表名
	
    ' 操作状态
	Private VALUE_VALIDATE	'2 表单值不为空则验证
	Private MUST_VALIDATE	'1 必须验证
	Private EXISTS_VALIDATE	'0 表单存在字段则验证
	Public patchValidate	'是否批处理验证
	
	'自动验证
	' mode分别为1(插入时验证),2(修改时验证),3(默认，前两种情况都验证)
	Public Function handle ( ByRef validate, ByRef data,ByRef mode )
		dim bValidate:bValidate = false
		'属性验证
		if not isEmpty(validate) Then	' 如果设置了数据自动验证则进行数据验证
			if patchValidate Then [error] = array()
			for each row in validate
				
                ' 验证因子定义格式
                ' array(field,rule,message,condition,type,when,params)
                ' 判断是否需要执行验证
				bValidate = false
				bound = ubound( row )
				if bound < 5 Then
					bValidate = true
				elseif 3 = row(5) OR mode = row(5) Then
						bValidate = true
				end If
				
				if bValidate Then
					if bound<2 Then		'前三项是必须的
						Call POP_MVC.Exit( "自动验证的每条数组不能少于三项 , " & "POPASP_AUTOVALIDATE:47" )
					End if
					
					if bound < 3 Then
						Redim Preserve row(3)
						row(3) = EXISTS_VALIDATE	'默认为存在就验证
					End If
					
					if bound < 4 Then
						Redim Preserve row(4)
						row(4) = "regex"	'默认采用正则验证
					End If
					
					'判断验证条件
					select case row(3)
						case MUST_VALIDATE	' 1 必须验证	
							if False = validationField(data,row) Then
								handle = false
								exit Function
							end if
						case VALUE_VALIDATE    '2  值不为空的时候才验证	
							
							if "" <> trim( data(row(0)) ) Then
								
								if false = validationField(data,row) Then
									handle = false
									exit Function
								end if
							End If
						Case else	' 0 默认表单存在该字段就验证
							if data.Exists( row(0) ) Then								
								if False = validationField(data,row) Then
									handle = false
									exit Function
								end if							
							end if				
					end select
				end if
			next
			
			if isArray( [error] ) Then
				if ubound([error]) >=0 Then
					handle = false
					exit function
				end If				
			end If
		end If
		handle = true
	End Function
	
	' 验证表单字段 仅支持批量验证
	Private Function validationField(data,row)
		dim bound
		if not validationFieldItem(data,row) Then
			if patchValidate Then
				bound = ubound([error])+1
				
				Redim Preserve [error]( bound )
				[error](bound) = row(2)
				validationField = null
				exit Function
			Else				
				[error] = row(2)
				validationField = false
				exit Function
			End If
		End If
		validationField = true
	End Function
	
	' 根据验证因子验证字段
	Private Function validationFieldItem(data,row)
		On Error Resume Next
		dim bound : bound = ubound(row)
		dim map,item,rs,str,arr,model,replace_str
		row(4) = LCase( row(4) )
		if row(4) = "function" OR row(4) = "callback" Then
			if bound = 6 Then
				if not isArray( row(6) ) Then row(6) = array( row(6) )						
				str =  "validationFieldItem = " &  "REPLACE_STR" & "( """ & data(row(0)) & ""","""  & join( row(6) , """,""" )  & """ )"
			else 
				str = "validationFieldItem = " & "REPLACE_STR" & "( """ & data(row(0)) & """ )"		
			end if
		End If
		
		select case row(4)
			case "callback"
				arr = split(row(1),".")
				model = arr(0)
				model = Replace(model,"Model","")
				set model = POP_MVC.Model( model )
				replace_str = "model." & arr(1)
			case "function"	'使用函数进行验证
				replace_str = row(1)
			case "confirm"	'验证两个字段是否相同
				validationFieldItem = (data( row(0) ) = data( row(1) ))
			case "unique"	'判断在表row(1)字段row(0)是否没有其它值了			
				if TypeName( row(0) ) = "String" Then
					if Instr( row(0) , "," ) > 0 Then
						row(0) = split( row(0) , "," )
					End If
					set map = POP_MVC.dict.Create()
					if IsArray( row(0) ) Then
						for each item in row(0)
							map.add item,data(item)
						next
					else 
						map.add row(0),data( row(0) )
					End If
					
					if trim(row(1)) <> "" Then
						set model = POP_MVC.Model( row(1) )
					elseif not isEmpty(tableName) Then
						set model = POP_MVC.Model( tableName )
					End if					
					
					if not isEmpty(model) Then
						'完善编辑的时候验证唯一
						if data.Exists( model.db.getPK() ) Then
							map.add model.db.getPK(),array( "neq" , data( model.db.getPK() ) )
						End If
						
						
						call model.db.where( map )						
						set rs = model.db.find()	
						if rs.RecordCount > 0 Then
							validationFieldItem = false
						Else 
							validationFieldItem = true
						End If
						call model.db.closeRS(rs)
						set model = nothing
					End if
				End If
			case "exists"	'判断在表row(1)字段row(0)是否还有其它值
				row(4) = "unique"
				validationFieldItem = (not validationFieldItem(data,row))
			case else
				validationFieldItem = check( data( row(0) ) , row(1) , row(4) )		
		End select
		if row(4) = "function" OR row(4) = "callback" Then 
			str = Replace( str , "REPLACE_STR" , replace_str )
			Execute str
		End if
		call L_( "POPASP_AUTOVALIDATE.validationFieldItem" )
	End Function
	
	Private Function in_array( val,arr )
		dim item
		for each item in arr 
			if item = val Then
				in_array = true
				exit function
			end if
		next
		in_array = false
	end Function
	
	'如果date1>date2返回正，否则返回负数
	Private Function dateCompare( date1,date2 )
		dateCompare = DateDiff("s",date2,date1)
	End Function
	
	'验证数据 支持 in notin between notbetween equal(eq) iequal(ieq) notequal(neq) length date regex expire ip_allow ip_deny,verify
	Function Check(value,rule,mode)		
		dim min,max,length
		mode = LCase( trim(mode) )
		select case mode
			case "in"	'此时的rule为range				
				if not isArray( rule ) Then
					rule = split( rule,"," )
				End if
				Check = in_array( value,rule )				
			case "notin","not in"
				Check = ( Not Check(value,rule,"in" ) )
			case "between"	'验证是否在某个范围
				if not isArray( rule ) Then
					rule = split(rule,",")
				end if
				min = CSng( trim(rule(0)) )
				max = CSng( trim(rule(1)) )
				value = CSng( value )
				
				Check = ( value >= min AND value <= max )
			case "notbetween","not between"
				Check = ( not Check(value,rule,"between") )
			case "eq","equal"
				Check = ( value = rule )
			case "ieq","iequal"
				Check = ( LCase(value) = LCase(rule) )
			case "verify"
				if rule<> "" then
					Check = ( UCase(value) = UCase(S_(rule)) )
				else
					Check = ( UCase(value) = UCase(S_("verify")) )
				end if
			case "neq","notequal"
				Check = ( Not Check(value,rule,"eq") )
			case "length"				
				length = len(value)
				if not isArray( rule ) Then
					rule = split(rule,",")
				end if
				if ubound( rule ) > 0 Then	'长度区间
					Check = ( length >= CLng(trim(rule(0))) AND length <= CLng(trim(rule(1))) )
				else 		'指定长度
					Check = ( length = rule(0) )
				End if
			case "date"
				check = isDate( value )
			case "expire"
				if not isArray( rule ) Then
					rule = split(rule,",")
				end if
				min = CDate(rule(0))
				max = CDate(rule(1))
				if Not isDate( value ) Then
					value = CDate(value)
				end if
				value = CDate(value)
				Check = (dateCompare(value,min) >=0 AND dateCompare(value,max) <=0)
			case "ip_allow"
				Check = in_array( get_client_ip() , split(rule,",") )
			case "ip_deny"
				Check = ( Not Check("",rule,"ip_allow") )
			case "regex"
				Check = regex(value,rule)
			case else
				Check = regex(value,rule)
		end Select	
	End Function
	
	'使用正则验证数据 require email url currency number zip integer double english chinese
	Public Function regex( value,rule )		
		dim dict,pattern	
		set dict = POP_MVC.dict.Create()
		dict.add "require", ".+"
		dict.add "email", "^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"
		dict.add "url","^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$"
		dict.add "currency","^\d+(\.\d+)?$"		
		dict.add "number","^\d+$"
		dict.add "zip","^\d{6}$"
		dict.add "integer","^[-\+]?\d+$"
		dict.add "double","^[-\+]?\d+(\.\d+)?$"		
		dict.add "english","^[A-Za-z]+$"		
		dict.add "chinese","^[\u4e00-\u9fa5]+$"		
		
		if dict.Exists( LCase(rule) ) Then
			pattern = dict(rule)			
		else 
			pattern = rule
		End If		
		regex = POP_MVC.String.reg_test(value,pattern,"")
		set dict = Nothing
	End Function
	
	Private Sub Class_Initialize
		EXISTS_VALIDATE = 0
		MUST_VALIDATE = 1
		VALUE_VALIDATE = 2
		patchValidate = False	
	End Sub
End Class
%>